<template>
  <div class="calendar-container">
    <div class="header" :class="{'no-slots': !$slots['header-left']||!$slots['header-right']}">
      <slot name="header-left"></slot>
      <div class="header-center">
        <span class="arrow-span arrow-left" @click="getDates('last')" />
        <span>{{ currentMonth }}</span>
        <span class="arrow-span arrow-right" @click="getDates('next')" />
      </div>
      <slot name="header-right"></slot>
    </div>
    <div class="top">
      <span v-for="(item, key) in weekMap" :key="key">{{ item }}</span>
    </div>
    <div class="center" :class="arrowDown ? 'arrow-up-center' : ''" @click="dayClick">
      <span
        v-for="(item, key) in day"
        :key="key"
        :class="selected===item ? 'active': ''"
      >{{ item }}</span>
    </div>
    <div class="footer" :class="arrowDown ? 'arrow-down-footer' : ''" @click="arrowClick">
      <img src="../../assets/images/arrow.png" alt="" srcset="">
    </div>
  </div>
</template>

<script>
import { getLastWeek, getNowMonthBegin, getNowMonthEnd, formart, getDayCountOfMonth } from '@/utils/dateUtils'
export default {
  data () {
    return {
      weekMap: ['一', '二', '三', '四', '五', '六', '日'],
      selected: '',
      arrowDown: false,
      dateList: [],
      currentMonth: '',
      firstDay: '',
      monthChangeFlag: '',
      slots: {}
    }
  },
  computed: {
    day () {
      let res = []
      const dates = this.dateList
      res = dates.map(val => {
        if (val) {
          return String(new Date(val).getDate())
        } else {
          return null
        }
      })
      return res
    }
  },
  created () {
    this.getDates('currentWeek')
  },
  methods: {
    // 获取显示的日期
    getDates (type) {
      const num = 1000 * 60 * 60 * 24

      let [start, end] = [null, null]
      if (type === 'last' || type === 'next') {
        type = this.arrowDown ? `${type}Month` : `${type}Week`
      }
      switch (type) {
        case 'currentWeek':
          [start, end] = [getLastWeek()[0].getTime(), getLastWeek()[1].getTime()]
          break
        case 'currentMonth':
          [start, end] = [getNowMonthBegin().getTime(), getNowMonthEnd().getTime()]
          break
        case 'lastMonth':
        case 'nextMonth':
          [start, end] = [this.getNewMonth(type)[0].getTime(), this.getNewMonth(type)[1].getTime()]
          break
        case 'lastWeek':
        case 'nextWeek':
          [start, end] = [this.getNewWeek(type)[0].getTime(), this.getNewWeek(type)[1].getTime()]
          break
        default:
          break
      }
      const diff = end - start
      const dateList = []
      for (let i = 0; i <= diff; i += num) {
        const newDay = start + i
        dateList.push(new Date(newDay))
      }
      const firstDay = dateList[0]
      this.firstDay = firstDay
      const dayOfWeek = firstDay.getDay() || 7
      if (dayOfWeek !== 1) {
        for (let j = 0; j < dayOfWeek - 1; j++) {
          dateList.unshift(null)
        }
      }
      this.dateList = dateList
      this.currentMonth = formart(new Date(start), 'yyyy年M月')
      return dateList
    },
    dayClick (e) {
      const { nodeName, outerText } = e.target
      if (nodeName.toLowerCase() === 'span') {
        this.selected = outerText
        let date = {}
        for (const val of this.dateList) {
          if (new Date(val).getDate() === Number(outerText)) {
            date = {
              date: val
            }
          }
        }
        this.$emit('select', date)
      }
    },
    // 点击展开箭头
    arrowClick () {
      this.arrowDown = !this.arrowDown
      const type = this.arrowDown ? 'currentMonth' : 'currentWeek'
      this.getDates(type)
    },
    // 获取上/下月
    getNewMonth (type) {
      const d = new Date(this.firstDay) // 获取原第一天所在的时间
      const currentYear = d.getFullYear() // 原第一天所在的年份
      const currentMonth = d.getMonth() // 原第一天所在的月份
      const num = type === 'lastMonth' ? -1 : 1 // 判断获取上个月还是下个月
      const newMonth = currentMonth + num // 要获取的新月份
      const start = new Date(d.setMonth(newMonth, 1)) // 新起始日期
      const startMonth = start.getMonth() // 新的月份数
      const total = getDayCountOfMonth(currentYear, newMonth) // 新月份的天数
      const end = new Date(d.setMonth(startMonth, total)) // 新终止日期
      return [start, end]
    },
    monthChange (type) {
      this.monthChangeFlag = type
    },
    // 获取上/下周
    getNewWeek (type) {
      const d = new Date(this.firstDay) // 获取原第一天所在的时间
      const currentDay = d.getDate() // 获取第一天的日期
      const currentMonth = d.getMonth() // 原第一天所在的月份
      const newStart = type === 'lastWeek' ? -7 : 7
      const newEnd = type === 'lastWeek' ? -1 : 13
      const start = new Date(d.setMonth(currentMonth, currentDay + newStart)) // 新起始日期
      const end = new Date(d.setMonth(currentMonth, currentDay + newEnd)) // 新终止日期
      return [start, end]
    }
  }
}
</script>

<style lang="less" scoped>
.calendar-container {
  .header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 88px;
    width: 100%;
    color: #16171C;
    font-size: 28px;

    .header-center {
      display: flex;
      align-items: center;
      width: auto;
      .arrow-span {
        display: inline-block;
        width: 60px;
        height: 60px;
        &::after {
          content: '';
          display: flex;
          width: 20px;
          height: 20px;
          border-radius: 2px;
          border-style: solid;
          border-width: 5px;
          border-color: #ccc transparent transparent #ccc;
        }
      }
      .arrow-left {
        transform: rotate(-53deg);
      }
      .arrow-right {
        transform: rotate(137deg);
      }
    }
  }
  .no-slots {
    justify-content: space-around;
  }
  .top {
    display: flex;
    height: 60px;
    line-height: 60px;
    justify-content: space-around;
    box-shadow: 0px 5px 20px #e2e2e2;
    color: #666666;
    span {
      display: flex;
      width: 11.6%;
      justify-content: center;
      align-items: center;
      margin: 0 10px;
    }
  }
  .center {
    display: flex;
    justify-content: flex-start;
    height: 80px;
    line-height: 80px;
    margin: 10px 0;
    span {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      margin: 10px;
      border-radius: 8px;
      color: #333333;
      font-size: 32px;
    }
    .active {
      background-color: #2A56C6;
      color: #fff;
    }
  }
  .arrow-up-center {
    height: 350px;
    justify-content: flex-start;
    flex-wrap: wrap;
    overflow-y: auto;
    span {
      display: flex;
      justify-content: center;
      width: 11.6%;
    }
  }
  .footer {
      position: relative;
      width: 100%;
      height: 15px;
      text-align: center;
      box-shadow: 0px -5px 20px #e2e2e2;
      img {
        transition: all .5s;
        position: absolute;
        width: 50px;
        height: 12px;
        top: 2px;
      }
    }
    .arrow-down-footer {
      transition: all .5s;
      img {
        transform: rotateX(180deg) ;
      }
    }
}
</style>
